package com.ideaaedi.zoo.example.springboot.dynamic.ds.shardingsphere.service;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.ideaaedi.commonmp.lite.transaction.DSManualTransactionSupport;
import com.ideaaedi.commonspring.transaction.DefaultManualTransactionSupport;
import com.ideaaedi.zoo.example.springboot.dynamic.ds.shardingsphere.mapper.MysqlStudentMapper;
import com.ideaaedi.zoo.example.springboot.dynamic.ds.shardingsphere.mapper.OracleTeacherMapper;
import com.ideaaedi.zoo.example.springboot.dynamic.ds.shardingsphere.po.StudentPO;
import com.ideaaedi.zoo.example.springboot.dynamic.ds.shardingsphere.po.TeacherPO;
import jakarta.annotation.Resource;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;

/**
 * 模拟service
 */
@Component
@SuppressWarnings("removal")
public class BizService4Basic {
    
    @Resource
    private MysqlStudentMapper mysqlStudentMapper;
    
    @Resource
    private OracleTeacherMapper oracleTeacherMapper;
    
    @Resource
    private BizShardingService bizShardingService;
    
    //    -------------------------- mysql部分 --------------------------
    // @DS("mysql") 不指定也可， 因为我们配置的默认数据源就是mysql
    public List<StudentPO> listStudent() {
        return mysqlStudentMapper.list();
    }
    
    @Transactional(rollbackFor = Exception.class)
    public void insertStudent(StudentPO student) {
        mysqlStudentMapper.insert(student);
    }
    
    @Transactional(rollbackFor = Exception.class)
    public void deleteAllStudent() {
        mysqlStudentMapper.deleteAll();
    }
    
    
    //    -------------------------- oracle部分 --------------------------
    @DS("oracle")
    public List<TeacherPO> listTeacher() {
        return oracleTeacherMapper.list();
    }
    
    @DS("oracle")
    @Transactional(rollbackFor = Exception.class)
    public void insertTeacher(TeacherPO teacher) {
        oracleTeacherMapper.insert(teacher);
    }
    
    @DS("oracle")
    @Transactional(rollbackFor = Exception.class)
    public void deleteAllTeacher() {
        oracleTeacherMapper.deleteAll();
    }
    
    
    //    -------------------------- 事务测试 --------------------------
    
    /**
     *
     * 可以用{@link DSTransactional}注解来管理多数据源事务
     */
    @DSTransactional
    public void testTx1() {
        insertThenOccurException();
    }
    
    /**
     *
     * 不可以用{@link Transactional}注解来管理多数据源事务
     */
    @Transactional
    public void testTx2() {
        insertThenOccurException();
    }
    
    /**
     * 可以用手动事务{@link DSManualTransactionSupport} 来管理多数据源事务
     */
    public void testTx3() {
        DSManualTransactionSupport.create().voidExec(this::insertThenOccurException);
    }
    
    /**
     * 不可以用手动事务{@link DefaultManualTransactionSupport} 来管理多数据源事务
     */
    public void testTx4() {
        DefaultManualTransactionSupport.create().voidExec(this::insertThenOccurException);
    }
    
    /**
     * 【多数据源】 正常往学生表(位于数据源A)、教师表(位于数据源B)、分表 插入数据后，再主动抛出异常
     */
    private void insertThenOccurException() {
        /*
         * 调用同一个类中的其他public方法时，是不会走代理.体现在本示例中即：@DS注解不会生效， 所以为了走代理，这里先获取到当前类的代理对象. 然后用代理对象调用即可
         * 注：需要启用@EnableAspectJAutoProxy(exposeProxy = true)，这里才能获取到当前代理对象
         */
        BizService4Basic bizService = (BizService4Basic)AopContext.currentProxy();
        
        // 插入
        bizService.insertStudent(StudentPO.builder().id(1).name("夏洛").build());
        System.out.println("插入mysql student完成了.");
        
        bizService.insertTeacher(TeacherPO.builder().id(1).name("蒋老师").build());
        System.out.println("插入oracle teacher完成了.");
    
        bizShardingService.insertSomeShardingData();
        System.out.println("插入sharding中的相关分表完成了.");
        
        Assert.isTrue(bizShardingService.listAll().size() > 0, "listAll should not be empty.");
        Assert.isTrue(bizService.listStudent().size() > 0, "student should not be empty.");
        Assert.isTrue(bizService.listTeacher().size() > 0, "teacher should not be empty.");
        
        // 使报错，促发事务回滚
        int a = 1/0;
    }
}